package org.example.java_gobang.game;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.example.java_gobang.JavaGobangApplication;
import org.example.java_gobang.model.User;
import org.example.java_gobang.model.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

/**
 * @author 86135
 */ //游戏房间

@Data
public class Room {
    private String roomId;
    // 玩家1
    private User user1;
    // 玩家2
    private User user2;
    // 先⼿⽅的⽤⼾ id
    private int whiteUserId = 0;
    // 棋盘, 数字 0 表⽰未落⼦位置. 数字 1 表⽰玩家 1 的落⼦. 数字 2 表⽰玩家 2 的落⼦
    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;
    private int[][] board = new int[MAX_ROW][MAX_COL];


    private ObjectMapper objectMapper = new ObjectMapper();

    private OnlineUserManager onlineUserManager;

    private RoomManager roomManager;

    private UserMapper userMapper;


    public Room() {
        // 使⽤ uuid 作为唯⼀⾝份标识
        roomId = UUID.randomUUID().toString();
        // 通过入口类中的 context 成员，手动获取到 RoomManager 和 OnlineUserManager
        onlineUserManager = JavaGobangApplication.ac.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.ac.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.ac.getBean(UserMapper.class);
        System.out.println("create Room: " + roomId + ", roomManager: " + roomManager);
    }

    // 添加一个棋盘，使用二维数组来表示。
    // 此处约定：
    // 1）使用 0 表示当前位置未落子。一个刚 new 好的二维数组，默认就是全 0，相当于是空的棋盘。
    // 2）使用 1 表示 user1 的落子位置
    // 3）使用 2 表示 user2 的落子位置
    public void putChess(String message) throws IOException {
        GameRequest req = objectMapper.readValue(message, GameRequest.class);
        GameResponse response = new GameResponse();
        // 1. 进⾏落⼦
        int chess = req.getUserId() == user1.getUserId() ? 1 : 2;
        int row = req.getRow();
        int col = req.getCol();
        if (board[row][col] != 0) {
            System.out.println("当前位置已经有子了!!! " + req);
            return;
        }
        board[row][col] = chess;//这里落子
        //控制台打印棋盘状态进行观察
//        printChessBoard();


        // 2. 检查游戏结束
        // 返回的 winner 为玩家的 userId
        int winner = checkWinner(chess, row, col);//每次上面落子后都会检查


        // 3. 把响应写回给玩家 拿到session
        response.setUserId(req.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);
        WebSocketSession session1 = onlineUserManager.getSessionFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getSessionFromGameRoom(user2.getUserId());

        if (session1 == null) {
            // 玩家1 掉线, 直接认为玩家2 获胜
            response.setWinner(user2.getUserId());
            System.out.println("玩家1 掉线!");
        }
        if (session2 == null) {
            // 玩家2 掉线, 直接认为玩家1 获胜
            response.setWinner(user1.getUserId());
            System.out.println("玩家2 掉线!");

        }
        //真正把服务器响应广播给两个玩家
        String responseJson = objectMapper.writeValueAsString(response);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(responseJson)); //真正把服务器响应广播给两个玩家
        }
        if (session2 != null) {
            session2.sendMessage(new TextMessage(responseJson)); //真正把服务器响应广播给两个玩家
        }
        // 4. 如果玩家胜负已分, 就把 room 从管理器中销毁
        if (response.getWinner() != 0) {
            int winUserId = response.getWinner();
            int loseUserId = response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
            System.out.println("游戏结束, 房间已经销毁! roomId: " + roomId + " 获胜⽅为: " + response.getWinner());
        }
    }

    private void printChessBoard() {
        System.out.println("打印棋盘信息: ");
        System.out.println("===========================");
        for (int r = 0; r < MAX_ROW; r++) {
            for (int c = 0; c < MAX_COL; c++) {
                System.out.print(board[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("===========================");
    }

    // 判定棋盘形式, 找出胜利的玩家.
    // 如果游戏分出胜负, 则返回玩家的 id.
    // 如果未分出胜负, 则返回 0
    // chess 值为 1 表⽰玩家1 的落⼦. 为 2 表⽰玩家2 的落⼦
    private int checkWinner(int chess, int row, int col) {
        // 以 row, col 为中⼼
        boolean done = false;

        // 1. 检查所有的⾏(循环五次)
        for (int c = col - 4; c <= col; c++) {
            if (c < 0 || c >= MAX_COL) {
                continue;
            }
            if (board[row][c] == chess
                    && board[row][c + 1] == chess
                    && board[row][c + 2] == chess
                    && board[row][c + 3] == chess
                    && board[row][c + 4] == chess) {
                done = true;
            }
        }
        // 2. 检查所有的列(循环五次)
        for (int r = row - 4; r <= row; r++) {
            if (r < 0 || r >= MAX_ROW) {
                continue;
            }
            if (board[r][col] == chess
                    && board[r + 1][col] == chess
                    && board[r + 2][col] == chess
                    && board[r + 3][col] == chess
                    && board[r + 4][col] == chess) {
                done = true;
            }
        }
        // 3. 检查左对⻆线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
                continue;
            }
            if (board[r][c] == chess
                    && board[r + 1][c + 1] == chess
                    && board[r + 2][c + 2] == chess
                    && board[r + 3][c + 3] == chess
                    && board[r + 4][c + 4] == chess) {
                done = true;
            }
        }
        // 4. 检查右对⻆线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
                continue;
            }
            if (board[r][c] == chess
                    && board[r + 1][c - 1] == chess
                    && board[r + 2][c - 2] == chess
                    && board[r + 3][c - 3] == chess
                    && board[r + 4][c - 4] == chess) {
                done = true;
            }
        }

        if (!done) {//任何胜利条件没满足就没有结束,就返回0,返回0给前端,前端不为0就不结束;
            return 0;
        }
        return chess == 1 ? user1.getUserId() : user2.getUserId();
    }

}
